package com.server.common.aspect;

import cn.hutool.core.util.StrUtil;
import com.server.common.annotation.RepeatSubmit;
import com.server.common.constants.RedisKeyConstant;
import com.server.common.exception.BusinessException;
import com.server.common.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * 请勿重复请求
 *
 * @author zgr
 * @date 2023/7/11 17:21
 */
@Component
@Slf4j
@Aspect
public class RepeatSubmitAspect {

    private final RedisUtil redisUtil;

    public RepeatSubmitAspect(RedisUtil redisUtil) {
        this.redisUtil = redisUtil;
    }

    /**
     * 定义切点
     */
    @Pointcut("@annotation(com.server.common.annotation.RepeatSubmit)")
    public void repeatSubmitAspect() {}

    @Around(value = "repeatSubmitAspect() && @annotation(repeatSubmit)")
    public Object around(ProceedingJoinPoint joinPoint, RepeatSubmit repeatSubmit) throws Throwable {

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 获取token当做key，小编这里是新后端项目获取不到哈，先写死
        String token = request.getHeader("token");
        if (StrUtil.isBlank(token)) {
            throw new BusinessException("token不存在，请登录！");
        }

        /**
         * rediskey=key:url
         */
        String redisKey = RedisKeyConstant.REPEAT_SUBMIT_KEY + request.getRequestURL();
        log.info("==========redisKey ====== {}",redisKey);

        if (!redisUtil.hasKey(redisKey)) {
            try {
                Object o = joinPoint.proceed();
                Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
                // 默认1秒内统一用户同一个地址同一个参数，视为重复提交
                redisUtil.set(redisKey, token, repeatSubmit.expireTime());
                return o;
            } catch (Exception e) {
                redisUtil.del(redisKey);
                throw new BusinessException(e.getMessage());
            }
        } else {
            // 抛出异常
            throw new BusinessException("请勿重复请求");
        }
    }
}
